Function.RegisterNamespace("xUnit.js");

xUnit.js.Mocks=new function(){
    // Public methods
    this.GetMock=function(target,member,mockery){
        if(target==undefined||!{"function":1,"object":1}[typeof(target)])throw new Error("xUnit.js.Mocks.GetMock: 'target' must be a valid Object.");
        if(!Object.IsType(String,member)||member.length==0)throw new Error("xUnit.js.Mocks.GetMock: 'member' must be a valid String.");
        var mockeries={};
        mockeries[member]=mockery;
        return this.GetMocks(target,mockeries);        
    };

    this.GetMocks=function(target,mockeries){
        if(target==undefined||!{"function":1,"object":1}[typeof(target)])throw new Error("xUnit.js.Mocks.GetMocks: 'target' must be a valid Object.");
        if(!Object.IsType(Object,mockeries))throw new Error("xUnit.js.Mocks.GetMock: 'mockeries' must be a valid Object containing member to mock mappings.");
        function Mockery(during,argument1,argument2,argumentN){
            if(!Object.IsType(Function,during))throw new Error("xUnit.js.Mocks.Mockery: 'during' must be a valid Function pointer.");
            var mockTargets=Object.Copy({},target,mockeries);
            try{
                for(var member in mockeries){
                    var mockery=mockeries[member];
                    var mocked=mockTargets[member];
                    if(mockery)mockery.Mocked=Object.IsType(Function,mocked)?Function.GetDelegate(mocked,target):mocked;
                    target[member]=mockery;
                }
                return during.apply(target,Array.prototype.slice.call(arguments,1));
            }catch(e){
                throw e;
            }finally{
                for(var member in mockeries){
                    var mockery=mockeries[member];
                    if(mockery)delete mockery.Mocked;
                    if(mockTargets.hasOwnProperty(member))target[member]=mockTargets[member];
                    else delete target[member];
                }
            }
        };
        Mockery.IsMock=true;
        return Mockery;
    };

    this.Mock=function(mock1,mock2,mockN){
        var mocks=Array.Copy(arguments);
        for(var i=0;i<mocks.length;i++){
            if(!Object.IsType(Function,mocks[i])||!mocks[i].IsMock)throw new Error("xUnit.js.Mocks.Mock: 'mock' must be a valid mockery, at position '"+(i+1)+"'.");
        }
        var currentMock=-1;
        return function ChainMock(during){
            if(++currentMock<mocks.length){
                return mocks[currentMock](function(){
                    return ChainMock(during);
                });
            }else{
                currentMock=-1;
                return during();
            }
        }
    };
};